package com.xinjian.jianba.utils;

import com.xinjian.jianba.exception.BusinessException;
import com.xinjian.jianba.exception.ResponseCode;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

public class HttpClientBase {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientBase.class);

    // 连接超时时间配置
    private static final int SOCKET_TIMEOUT = 10000;

    private static final int CONNECT_TIMEOUT = 15000;

    // 要访问的服务器内容的路径
    private String urlStr;

    // URL参数
    private Map<String, String> pramas;

    /**
     * 使用Post方式访问服务器资源.
     */
    public String doPost() throws BusinessException {

        if (urlStr == null) {
            throw new BusinessException(ResponseCode.ERROR, "url is null!");
        }
        LOGGER.info("param====>url:" + urlStr);
        LOGGER.info("param====>pramas:" + JsonUtil.getJsonString(pramas));

        try {
            // Post方法对象
            HttpPost httpPost = new HttpPost(urlStr);

            // 传递的参数对象
            List<NameValuePair> parameters = new ArrayList<NameValuePair>();
            parameters.add(new BasicNameValuePair("par", "request-post"));

            // 如果请求对象需要传递对象，此处用户遍历传入的参数，然后赋给parameters
            if (!CollectionUtils.isEmpty(pramas)) {
                Iterator<Entry<String, String>> it = pramas.entrySet().iterator();
                Entry<String, String> entry = null;

                while (it.hasNext()) {
                    entry = it.next();
                    parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
            }

            // 设置请求参数
            HttpEntity entity = new UrlEncodedFormEntity(parameters, "UTF-8");
            httpPost.setEntity(entity);
            return client(httpPost);
        } catch (Exception e) {
            LOGGER.info("httpClient --- doPostException" + e);
        }

        return null;
    }

    /**
     * 使用Post方式访问服务器资源(入参非键值对).
     */
    public String doPost(String data, String url) throws Exception {
        LOGGER.info("param====>data:" + data + "url:" + url);
        // Post方法对象
        HttpPost httpPost = new HttpPost(url);
        // 设置报文头
        httpPost.addHeader("Content-Type", "application/json");
        // 设置报文体(UTF-8 格式)
        StringEntity se = new StringEntity(data, "UTF-8");
        httpPost.setEntity(se);

        return client(httpPost);
    }

    /**
     * 使用Get方式访问服务器资源.
     *
     */
    public String doGet() throws Exception {
        if (urlStr == null) {
            throw new NullPointerException("url is null!");
        }
        LOGGER.info("param====>url:" + urlStr);

        // Get请求对象
        HttpGet httpGet = new HttpGet(getUrlAddPramas(urlStr, pramas));
        return client(httpGet);
    }

    /**
     * 接收一个HttpRequestBase（一般为，HttpPost和HttpGet）对象，然后向服务器发送请求，获取资源，返回一个完整的XML文件.
     */
    private String client(HttpRequestBase request) throws Exception {

        CloseableHttpClient httpclient = HttpClientBuilder.create().build();
        CloseableHttpResponse response = null;

        try {

            // 设置请求和传输超时时间
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(SOCKET_TIMEOUT)
                    .setConnectTimeout(CONNECT_TIMEOUT).build();
            request.setConfig(requestConfig);

            response = httpclient.execute(request);

            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    return EntityUtils.toString(entity, "UTF-8");
                }
            } else {
                throw new BusinessException(response.getStatusLine().getStatusCode(), response.toString());
            }
        } catch (Exception e) {
            LOGGER.info("httpClientException" + e);
        } finally {
            // 关闭连接,释放资源
            try {
                if (response != null) {
                    response.close();
                }

                if (httpclient != null) {
                    httpclient.close();
                }
            } catch (Exception e) {
                LOGGER.info("closeClientException" + e);
            }
        }

        return null;
    }

    /**
     * 将传入的参数组织成一个字符串.
     */
    private String getUrlAddPramas(String url, Map<String, String> pramasMap) {

        StringBuffer sb = new StringBuffer();

        if (pramasMap == null || pramasMap.isEmpty()) {
            return url;
        }

        sb.append(url + "?");

        Iterator<Entry<String, String>> it = pramas.entrySet().iterator();
        Entry<String, String> entry = null;

        while (it.hasNext()) {
            entry = it.next();
            sb.append(entry.getKey() + "=" + entry.getValue() + "&");
        }

        String result = sb.toString();
        if (result != null && result.trim().length() > 0) {
            result = result.substring(0, result.length() - 1);
        }

        return result;
    }

    public String getUrlStr() {
        return urlStr;
    }

    public void setUrlStr(String urlStr) {
        this.urlStr = urlStr;
    }

    public Map<String, String> getPramas() {
        return pramas;
    }

    public void setPramas(Map<String, String> pramas) {
        this.pramas = pramas;
    }

}
